package me.gavin.util

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import androidx.core.content.FileProvider
import me.gavin.BuildConfig
import me.gavin.di.instanceHolder
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.math.BigDecimal
import java.util.*


/**
 * 缓存助手
 *
 * @author gavin.xiong 2017/4/28
 */
object CacheHelper {

    /**
     * 获取sd卡根目录
     */
    val appDir: String?
        get() = if (Environment.MEDIA_MOUNTED != Environment.getExternalStorageState()) null else
            "${Environment.getExternalStorageDirectory().absolutePath}${File.separator}sosolx${File.separator}".also {
                val appDir = File(it)
                if (!appDir.exists()) {
                    appDir.mkdirs()
                }
            }

    /**
     * 获取缓存文件夹 ( sdCard
     * -    ? /storage/sdcard0/Android/data/com.example.dir/cache
     * -    : /data/data/com.example.dir/cache )
     */
    val cacheDir: String
        get() = if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() && instanceHolder.get<Context>().externalCacheDir != null) {
            instanceHolder.get<Context>().externalCacheDir!!.path
        } else {
            instanceHolder.get<Context>().cacheDir.path
        }

    /**
     * 获取缓存文件夹 ( sdCard
     * -    ? /storage/sdcard0/Android/data/com.example.dir/files
     * -    : /data/data/com.example.dir/files )
     */
    fun getFilesDir(type: String): String =
            if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() && instanceHolder.get<Context>().getExternalFilesDir(type) != null) {
                instanceHolder.get<Context>().getExternalFilesDir(type)!!.path
            } else {
                instanceHolder.get<Context>().filesDir.path
            }

    fun getPublicDir(type: String): String = Environment.getExternalStoragePublicDirectory(type).path

    /**
     * 格式化单位
     *
     * @param size size
     * @return size
     */
    private fun getFormatSize(size: Double): String {

        val kiloByte = size / 1024
        if (kiloByte < 1) {
            return size.toString() + "B"
        }

        val megaByte = kiloByte / 1024
        if (megaByte < 1) {
            val result1 = BigDecimal(java.lang.Double.toString(kiloByte))
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"
        }

        val gigaByte = megaByte / 1024
        if (gigaByte < 1) {
            val result2 = BigDecimal(java.lang.Double.toString(megaByte))
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"
        }

        val teraBytes = gigaByte / 1024
        if (teraBytes < 1) {
            val result3 = BigDecimal(java.lang.Double.toString(gigaByte))
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"
        }
        val result4 = BigDecimal(teraBytes)

        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"
    }


    @Throws(IOException::class)
    fun getCacheSize(): String? {
        return try {
            getFormatSize(File(cacheDir).folderSize.toDouble())
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }

    private val File.folderSize: Long
        get() = listFiles()
                ?.map {
                    if (it.isDirectory) it.folderSize else it.length()
                }
                ?.sum() ?: 0L

    fun path2Uri(context: Context, imagePath: String): Uri? {
        val cursor = context.contentResolver.query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                arrayOf(MediaStore.Images.Media._ID),
                MediaStore.Images.Media.DATA + " = ? ",
                arrayOf(imagePath), null)
        return cursor?.use {
            return if (it.moveToFirst()) {
                Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        it.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)).toString())
            } else null
        } ?: if (File(imagePath).exists()) {
            val values = ContentValues()
            values.put(MediaStore.Images.Media.DATA, imagePath)
            context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        } else null
    }

    fun path2Uri2(context: Context, path: String): Uri? {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            FileProvider.getUriForFile(context, context.packageName + ".fileProvider", File(path))
        } else {
            Uri.parse("file://$path")
        }
    }

    fun uri2Path(context: Context, uri: Uri): String? {
        val cursor = context.contentResolver.query(uri,
                arrayOf(MediaStore.MediaColumns.DATA), null, null, null)
        return cursor?.use {
            return if (it.moveToFirst()) {
                it.getString(it.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA))
            } else null
        }
    }

    /**
     * 质量压缩
     */
    fun compressByQuality(bitmap: Bitmap, maxLength: Long = 1024 * 1000 * 2): String {
        var options = 100
        val baos = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos)
        while (baos.toByteArray().size > maxLength) {
            baos.reset()
            options = maxOf(0, options - 10)
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos)
            if (options == 0) break
        }
        val path = "$cacheDir/${UUID.randomUUID()}.jpg"
        FileOutputStream(path).use {
            it.write(baos.toByteArray())
            it.flush()
        }
        return path
    }

    /**
     * 采样压缩
     */
    fun compressBySampling(url: Uri, maxSize: Int = 1024 * 2): String? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeStream(instanceHolder.get<Context>().contentResolver.openInputStream(url), null, options)
        val scale = maxOf(options.outWidth, options.outHeight).toDouble() / maxSize
        options.inSampleSize = Math.ceil(scale).toInt()
        options.inPreferredConfig = Bitmap.Config.RGB_565
        options.inJustDecodeBounds = false
        val bitmap = BitmapFactory.decodeStream(instanceHolder.get<Context>().contentResolver.openInputStream(url), null, options)
        return bitmap?.let { compressByQuality(it) }
    }


    fun saveBitmap(bitmap: Bitmap, imgPath: String, withUpdate: Boolean = false) {
        FileOutputStream(imgPath).use {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
        }
        if (withUpdate) {
            updateAlbum(instanceHolder.get(), imgPath)
        }
    }

    /**
     * 通知相册更新
     */
    fun updateAlbum(context: Context, path: String) {
        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                Uri.parse("file://$path")))
    }

}
